package com.aphrodite.ui.widgets.barcode;

import java.util.Vector;

/**
 * 
 * 
 * The Interleave 2 of 5 barcode requires an even number of characters. At the
 * same time, a modulo 10 check digit can be used. The default constructor
 * presumes that if the barcode is of an odd length, then a check digit is
 * required. This will automaticaly be generated. If the constructor with the
 * check digit flag is used, the check digit flag is flase and the length of the
 * barcode is odd, then an exception will be thrown.
 * 
 * @author <a href="mailto:james@metalskin.com">James Jenner</a>
 */
class Int2of5Barcode extends Std2of5Barcode {

	static class ModuleTemplate extends Std2of5Barcode.ModuleTemplate {
		public static final Module END_CHAR = new Module(new int[] { 3, 1, 1 });
		public static final Module START_CHAR = new Module(new int[] { 1, 1, 1, 1 });

		/**
		 * Returns the module that represents the specified characters.
		 * Interleave uses one character for the bars and the other for the
		 * spaces, so for each 'module' two characters are required to determine
		 * the resulting module.
		 * 
		 * @param barValue
		 *            The data character for the bars
		 * @param spaceValue
		 *            The data character for the spaces
		 * @return The module that encodes the given characters
		 */
		static Module getModule(String barValue, String spaceValue) {
			Module module = null;
			int[] bar = null;
			int[] space = null;
			bar = (int[]) SET.get(barValue);
			space = (int[]) SET.get(spaceValue);

			// this should always be true, but best to check just in case...
			if (bar != null && bar.length == 5 && space != null && space.length == 5) {

				// create the new module based on the selected bar val and space
				// val
				module = new Module(new int[] { bar[0], space[0], bar[1], space[1], bar[2], space[2], bar[3], space[3],
						bar[4], space[4] });
				module.setSymbol(barValue + spaceValue);
			}

			return module;
		}

		/**
		 * No public access.
		 */
		protected ModuleTemplate() {}
	}

	/**
	 * Indicates whether the given character is valid for this barcode or not.
	 * This basically just checks to see whether the key is in the list of
	 * encoded characters.
	 * 
	 * @param key
	 *            The key to check for validity
	 * @return True if the key is valid, false otherwise
	 */
	static boolean isValid(String key) {
		return ModuleTemplate.SET.containsKey(key);
	}

	/**
	 * Constructs a new Interleave 2 of 5 barcode with thte specified data.
	 * 
	 * @param data
	 *            The data to encode
	 * @param checkDigit
	 *            if true then a check digit is automaticaly appened to data
	 * @throws BarcodeException
	 *             If the data is invalid
	 */
	Int2of5Barcode(String data, boolean checkDigit, int height) throws BarcodeException {
		super(checkDigit ? data + Modulo10.getMod10CheckDigit(data, 3) : data, false, height);
	}

	/**
	 * Encodes the data of the barcode into bars.
	 * 
	 * @return The encoded bar data
	 */
	protected Module[] encodeData() {
		Vector modules = new Vector();

		for (int i = 0; i < data.length() - 1; i += 2) {
			Module module = ModuleTemplate
					.getModule(String.valueOf(data.charAt(i)), String.valueOf(data.charAt(i + 1)));

			modules.addElement(module);
		}
		Module[] ret = new Module[modules.size()];
		modules.copyInto(ret);
		return ret;
	}

	/**
	 * Returns the post-amble for the barcode.
	 * 
	 * @return A BlankModule
	 */
	protected Module getPostAmble() {
		return ModuleTemplate.END_CHAR;
	}

	/**
	 * Returns the pre-amble for the barcode.
	 * 
	 * @return A BlankModule
	 */
	protected Module getPreAmble() {
		return ModuleTemplate.START_CHAR;
	}

	protected void validateData() throws BarcodeException {
		if (data.length() % 2 != 0) {
			throw new BarcodeException("The Interleave 2 of 5 encoding requires an even number of data");
		}

		super.validateData();
	}
}
